package com.nokia.ion.sdu.cdr_decoder;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.*;

public class Main {
    private static int numOfReader = 5;
    public static int outputType = 1;

    public static String hostname;

    private static CountDownLatch countDownLatch;

    private static Configuration configuration;

    public static Date startTime;
    public static Date endTime;

    public static File rawCdrDir;

    private static List<File> rawCdrFileList = new LinkedList<>();

    public static void main(String[] args) {

        init();

        long start = System.currentTimeMillis();

        countDownLatch = new CountDownLatch(1);
        LoopPrint lp = new LoopPrint(numOfReader, countDownLatch);
        lp.start();

        LinkedBlockingQueue<Cdr> queue = new LinkedBlockingQueue<>(1000);
        ExecutorService es = Executors.newFixedThreadPool(numOfReader);

        Thread cdrWriter = null;
        try {
            switch (outputType) {
                case 1:
                    cdrWriter = new Thread(new Sqlite3Writer(queue, configuration));
                    break;
                case 2:
                    cdrWriter = new Thread(new MysqlWriter(queue, configuration));
                    break;
                case 3:
                    cdrWriter = new Thread(new ElasticsearchWriter(queue, configuration));
                    break;
                case 4:
                    cdrWriter = new Thread(new AnalysisWriter(queue, configuration));
                    break;
                default:
                    System.exit(-1);
            }
            cdrWriter.start();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }

        for (int i = 0; i < numOfReader; i++) {
            es.execute(new ParseThread(i, startTime.getTime(), endTime.getTime(), queue, configuration));
        }
        try {
            es.shutdown();
            es.awaitTermination(3, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            es.shutdownNow();
        }

        try {
            Cdr cdr = new Cdr();
            cdr.last = true;
            queue.put(cdr);
        } catch (InterruptedException e) {
            e.printStackTrace();
            if (cdrWriter != null) {
                cdrWriter.interrupt();
            }
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long dur = (System.currentTimeMillis() - start) / 1000;
        System.out.println("All task finished. used time " + dur + " sec");
    }

    private static void init() {
        try {
            configuration = Configuration.parseConfiguration();

            startTime = Cdr.localFormat.parse(configuration.startTime);
            endTime = Cdr.localFormat.parse(configuration.endTime);
            System.out.println("starttime " + configuration.startTime + ", endtime " + configuration.endTime);

            if (configuration.outputType.equals("sqlite3")) {
                outputType = 1;
            } else if (configuration.outputType.equals("mysql")) {
                outputType = 2;
            } else if (configuration.outputType.equals("elasticsearch")) {
                outputType = 3;
            } else if (configuration.outputType.equals("analysis")) {
                outputType = 4;
            } else {
                System.err.println("outputType not valid.");
                System.exit(-1);
            }

            rawCdrDir = new File(configuration.rawCdrDir);
            if (!rawCdrDir.exists()) {
                System.err.println("raw CDRs source dir not exist");
                System.exit(-1);
            }
            if (configuration.rawCdrFiles.length == 0) {
                findFiles(rawCdrDir, "rawdata");
            } else {
                for (String file : configuration.rawCdrFiles) {
                    rawCdrFileList.add(new File(rawCdrDir, file));
                }
            }

            numOfReader = configuration.numOfReadThread;
            if (numOfReader <= 0) {
                numOfReader = 5;
            }
            if (numOfReader > rawCdrFileList.size()) {
                numOfReader = rawCdrFileList.size();
            }

            hostname = getHostName();
            if (hostname == null || hostname.length() == 0) {
                hostname = "unknown_hostname";
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    private static int nextFileIdx = 0;
    public static synchronized File nextSourceFile() {
        if (nextFileIdx < rawCdrFileList.size()) {
            System.out.println("number of rawCdrFiles:" + rawCdrFileList.size() + ", left: " + (rawCdrFileList.size() - nextFileIdx - 1));
            return rawCdrFileList.get(nextFileIdx++);
        }

        return null;
    }

    private static void findFiles(File baseDir, final String namePrefix) {
        if (!baseDir.exists() || !baseDir.isDirectory()){
            return;
        }

        File[] files = baseDir.listFiles();
        for (File f : files) {
            if (f.isDirectory()) {
                findFiles(f, namePrefix);
            } else {
                if (f.getName().startsWith(namePrefix)) {
                    rawCdrFileList.add(f);
                }
            }
        }
    }

    private static String getHostNameForLiunx() {
        try {
            return (InetAddress.getLocalHost()).getHostName();
        } catch (UnknownHostException uhe) {
            String host = uhe.getMessage(); // host = "hostname: hostname"
            if (host != null) {
                int colon = host.indexOf(':');
                if (colon > 0) {
                    return host.substring(0, colon);
                }
            }
            return "UnknownHost";
        }
    }

    public static String getHostName() {
        if (System.getenv("COMPUTERNAME") != null) {
            return System.getenv("COMPUTERNAME");
        } else {
            return getHostNameForLiunx();
        }
    }

//    @SuppressWarnings("deprecation")
//    private static Date timestampToDate(String ts) {
//        int year = Integer.parseInt(ts.substring(0, 4));
//        int month = Integer.parseInt(ts.substring(4, 6)) - 1;
//        int day = Integer.parseInt(ts.substring(6, 8));
//        int hour = Integer.parseInt(ts.substring(8, 10));
//        int minute = Integer.parseInt(ts.substring(10, 12));
//        int second = Integer.parseInt(ts.substring(12, 14));
//
//        Calendar c = Calendar.getInstance();
//        c.set(year, month, day, hour, minute, second);
//        return c.getTime();
//    }

    static int bytes2int(byte b[]) {
        int s;
        s = ((((b[0] & 0xff) << 8 | (b[1] & 0xff)) << 8) | (b[2] & 0xff)) << 8
                | (b[3] & 0xff) | (b[4] & 0xff) | (b[5] & 0xff) | (b[6] & 0xff) | (b[7] & 0xff);
        return s;
    }
}
